package com.ymx.darling.executor.mapping.handler;

import com.ymx.darling.bean.sql.Statement;
import com.ymx.darling.executor.mapping.metadata.MetaData;
import com.ymx.darling.executor.mapping.metadata.MetaDataManager;
import com.ymx.darling.type.TypeHandler;
import com.ymx.darling.util.ReflectUtil;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 *
 * map的类型映射器<br/>
 * ResultSet的每一条记录映射为一个Map
 * 将所有的Map放入List并返回
 *
 * @author 爱java的小于
 */
public class MapResultSetHandler implements ResultSetHandler<Map<String,Object>> {
    private final Statement statement;
    private List<MetaData> cursorMetaDataList;

    public MapResultSetHandler(Statement statement) {
        this.statement = statement;
    }

    @Override
    public List<Map<String, Object>> handle(ResultSet resultSet) throws SQLException {
        List<Map<String, Object>> resultMapList = new ArrayList<>();
        List<MetaData> metaDataList = this.getMetaDataList(resultSet);
        while (resultSet.next()) {
            resultMapList.add(this.mapping(resultSet, metaDataList));
        }
        return resultMapList;
    }


    /**
     * 返回结构集中元数据信息 为每个元数据添加类型处理器
     * @param resultSet resultSet
     * @return list
     */
    private List<MetaData> getMetaDataList(ResultSet resultSet) throws SQLException {
        //获取结果集元数据信息
        List<MetaData> metaDataList = MetaDataManager.getMetaDataList(resultSet);
        //添加结果集映射器
        MetaDataManager.addTypeHandler(metaDataList);

        return metaDataList;
    }


    @Override
    public Map<String, Object> handleCursor(ResultSet resultSet) throws SQLException {
        if (this.cursorMetaDataList == null) {
            this.cursorMetaDataList = this.getMetaDataList(resultSet);
        }
        return this.mapping(resultSet, this.cursorMetaDataList);
    }


    /**
     * 结果集数据映射为Map类型数据
     *
     * @param resultSet 结果集数据
     * @param metaDatumObjects 结果集字段信息封装类型
     * @return List
     * @throws SQLException 可能会抛出此异常
     */
    private Map<String,Object> mapping(ResultSet resultSet, List<MetaData> metaDatumObjects)throws SQLException{
        final Class<?> mapClass = this.statement.getModule();
        Map<String, Object> mapEntity = ReflectUtil.newInstanceMap(mapClass);
        for(int i = metaDatumObjects.size() - 1; i > -1; --i){
            final MetaData md = metaDatumObjects.get(i);
            final TypeHandler<?> convertHandler = md.getTypeHandler();
            final String key = md.getName();
            final Object value = convertHandler.getResult(resultSet, md.getIndex());
            mapEntity.put(key, value);
        }
        return mapEntity;
    }
}
